package cn.org.xuanguang.kepler.hormos.orm.dao;


import cn.org.xuanguang.kepler.hormos.orm.acl.IPolicyInterceptorChain;
import cn.org.xuanguang.kepler.hormos.orm.result.PagerResult;
import cn.org.xuanguang.kepler.hormos.rdb.dml.Dml;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.delete.DeleteOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.delete.DeleteOperatorResulet;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.insert.InsertOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.insert.InsertOperatorResulet;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.update.UpdateOperatorParameter;
import cn.org.xuanguang.kepler.hormos.rdb.dml.operator.update.UpdateOperatorResulet;
import cn.org.xuanguang.kepler.hormos.rdb.dml.warrper.ResultWrappers;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.execute.Delete;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.execute.Update;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.param.QueryParam;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.param.Term;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.param.TermType;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.param.UpdateParam;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.sql.BatchSqlRequest;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.sql.DefaultBatchSqlRequest;
import cn.org.xuanguang.kepler.hormos.rdb.dsl.sql.SqlRequests;
import cn.org.xuanguang.kepler.hormos.rdb.entity.IEntity;
import cn.org.xuanguang.kepler.hormos.rdb.executor.SyncSqlExecutor;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.mapper.JpaColumnMapper;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.mapper.JpaEntityMapper;
import cn.org.xuanguang.kepler.metadata.relational.KeplerMetaTable;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;


public class DefaultSyncRepository<E, K> implements HormsBaseSyncRepository<E, K> {

    private Class<E> tableTye;

    private SyncSqlExecutor syncSqlExecutor;

    private KeplerMetaTable metaTable;

    @Getter
    @Setter
    private Dml dml;

    public DefaultSyncRepository(SyncSqlExecutor syncSqlExecutor, Class<E> entityType, IPolicyInterceptorChain policyInterceptorChain) {
        this.syncSqlExecutor = syncSqlExecutor;
        this.tableTye = entityType;
        this.metaTable = JpaEntityMapper.of(entityType).getMetaTable();
        this.dml = Dml.of(syncSqlExecutor, syncSqlExecutor.getDataSourceType().getValue(), policyInterceptorChain);
    }


    @Override
    public SyncSqlExecutor getSyncSqlExecutor() {
        return this.syncSqlExecutor;
    }

    @Override
    public String getDialect() {
        return this.syncSqlExecutor.getDataSourceType().getValue();
    }

    @Override
    public InsertOperatorResulet insert(E data) {
        if (data == null) {
            throw new IllegalArgumentException("Entity data cannot be null");
        }
        // Column information
        JpaEntityMapper<E> entityMapper = JpaEntityMapper.of(tableTye).dsl(data);
        InsertOperatorParameter insertOperatorParameter = entityMapper.insert(dml.createInsertOperator().getOperatorParameter());
        return dml.createInsertOperator()
                .insert(insertOperatorParameter)
                .execute();
    }

    @Override
    public InsertOperatorResulet insertBatch(Collection<E> data) {
        List<InsertOperatorParameter> insertOperatorParameterList = new ArrayList<>();

        if (data == null || data.isEmpty()) {
            throw new IllegalArgumentException("Entity data cannot be null");
        }

//        List<Term> list = dml.createInsertOperator().getOperatorParameter().getTerms();
//        // 默认列信息
//        List<String> columns = dml.createInsertOperator().getOperatorParameter().getColumns();


//        遍历生成批量插入sql
        data.stream().forEach(e -> {
            if (data == null) {
                throw new IllegalArgumentException("Entity data cannot be null");
            }
            JpaEntityMapper<E> entityMapper = JpaEntityMapper.of(tableTye).dsl(e);
            // 添加策略条件
            InsertOperatorParameter insertOperatorParameter = dml.createInsertOperator().getOperatorParameter();
//            insertOperatorParameter.setTerms(list);
            insertOperatorParameterList.add( entityMapper.insert(insertOperatorParameter));
        });

        return dml.createInsertOperator().insertBatch(insertOperatorParameterList).execute();
    }

    @Override
    public UpdateOperatorResulet updateById(E data) {
        if (data == null) {
            throw new IllegalArgumentException("Entity data cannot be null");
        }
        // Column information
        JpaEntityMapper<E> entityMapper = JpaEntityMapper.of(tableTye).dsl(data);
        UpdateParam<E> updateParam = new UpdateParam<>(data);
        metaTable.getPrimaryKeys().forEach(pk -> {
            getJpaColumnMapperList(data).forEach(jpaColumnMapper -> {
                if (pk.equals(jpaColumnMapper.getColumn())) {
                    updateParam.and(jpaColumnMapper.getColumn(), "=", jpaColumnMapper.getValue());
                }
            });
        });
        if (updateParam.getTerms().isEmpty()) {
            throw new IllegalArgumentException("Entity ID cannot be null");
        }

        Update<E, ?> update = Update.of(updateParam);
        UpdateOperatorParameter updateOperatorParameter = entityMapper.update(update);
        return dml.createUpdateOperator()
                .table(updateOperatorParameter.getTableName())
                .where(updateOperatorParameter.getTerms())
                .columns(updateOperatorParameter.getColumns())
                .values(updateOperatorParameter.getValues())
                .execute();
    }

    @Override
    public DeleteOperatorResulet delete(E data) {
        if (data == null) {
            throw new IllegalArgumentException("Entity data cannot be null");
        }
        JpaEntityMapper entityMapper = JpaEntityMapper.of(tableTye).dsl((IEntity) data);
        Delete delete = Delete.of();
        getJpaColumnMapperList(data).forEach(jpaColumnMapper -> {
            if (jpaColumnMapper.getValue() != null) {
                delete.and(jpaColumnMapper.getColumn(), TermType.eq, jpaColumnMapper.getValue());
            }
        });
        DeleteOperatorParameter deleteOperatorParameter = entityMapper.delete(delete);
        return dml.createDeleteOperator()
                .table(deleteOperatorParameter.getTableName())
                .where(deleteOperatorParameter.getTerms())
                .execute();
    }



    @Override
    public DeleteOperatorResulet deleteById(K id) {
        Delete delete = Delete.of();
        // Column information
        metaTable.getPrimaryKeys().forEach(pk -> {
            delete.and(pk, "=", id);
        });
        JpaEntityMapper entityMapper = JpaEntityMapper.of(tableTye);
        DeleteOperatorParameter deleteOperatorParameter = entityMapper.delete(delete);
        return dml.createDeleteOperator()
                .table(deleteOperatorParameter.getTableName())
                .where(deleteOperatorParameter.getTerms())
                .execute();
    }

    @Override
    public E queryById(K primaryKey) {
        if (primaryKey == null) {
            throw new IllegalArgumentException("Primary key cannot be null");
        }
        final String idColumn = metaTable.getPrimaryKeys().stream().findFirst().orElseThrow(() -> new RuntimeException("Entity ID column not found"));
        return (E) dml.createSelectOperator()
                .from(metaTable.getTableName())
                .select(metaTable.getColumns().stream().map(c -> c.getColumnName()).toArray(String[]::new))
                .and(idColumn, TermType.eq, primaryKey)
                .setWrapper(ResultWrappers.singleObject(tableTye))
                .execute().getResult();
    }
    @Override
    public E queryFirst(QueryParam queryParam) {
        List<E> list =    (List<E>) getDml().createSelectOperator()
                .from(metaTable.getTableName())
                .select(metaTable.getColumns().stream().map(c -> c.getColumnName()).toArray(String[]::new))
                .where(queryParam.getTerms())
                .setWrapper(ResultWrappers.toList(tableTye))
                .execute().getResult();
        return  list.stream().findFirst().orElse(null);
    }
    @Override
    public List<E> queryById(K... primaryKey) {
        if (primaryKey == null || primaryKey.length == 0) {
            throw new IllegalArgumentException("Primary keys cannot be null or empty");
        }
        final String idColumn = metaTable.getPrimaryKeys().stream().findFirst().orElseThrow(() -> new RuntimeException("Entity ID column not found"));
        return (List<E>) dml.createSelectOperator()
                .from(metaTable.getTableName())
                .select(metaTable.getColumns().stream().map(c -> c.getColumnName()).toArray(String[]::new))
                .in(idColumn, primaryKey)
                .setWrapper(ResultWrappers.toList(tableTye))
                .execute().getResult();
    }

    @Override
    public List<E> queryById(Collection<K> primaryKey) {

        if (primaryKey == null || primaryKey.isEmpty()) {
            throw new IllegalArgumentException("Primary key collection must not be null or empty");
        }
        final String[] idColumn = {""};
        // 获取 id字段信息
        metaTable.getPrimaryKeys().forEach(pk -> {
            idColumn[0] = pk;
        });

        if (idColumn[0].isEmpty()) {
            throw new RuntimeException("entity id is null");
        }

        return (List<E>) getDml().createSelectOperator()
                .from(metaTable.getTableName())
                .select(metaTable.getColumns().stream().map(c -> c.getColumnName()).toArray(String[]::new))
                .in(idColumn[0], primaryKey.toArray())
                .setWrapper(ResultWrappers.toList(tableTye))
                .execute().getResult();
    }

    /**
     * 查询所有元素并返回一个列表。
     * <p>此方法覆盖了基类的queryAll方法，实现了对所有元素的查询。然而，当前实现返回一个空列表，
     * 适用于不需要具体实现查询所有元素的场景，或者为了提供一个默认的、不可修改的空列表。</p>
     *
     * @return 返回一个不可修改的空列表。列表类型为泛型E，符合泛型编程的最佳实践。
     */
    @Override
    public List<E> queryAll() {
        return (List<E>) getDml().createSelectOperator()
                .from(metaTable.getTableName())
                .select(metaTable.getColumns().stream().map(c -> c.getColumnName()).toArray(String[]::new))
                .setWrapper(ResultWrappers.toList(tableTye))
                .execute().getResult();
    }


    @Override
    public PagerResult query(QueryParam queryParam) {
        int total = count(queryParam);
        List<E> list = (List<E>) getDml().createSelectOperator()
                .from(metaTable.getTableName())
                .select(metaTable.getColumns().stream().map(c -> c.getColumnName()).toArray(String[]::new))
                .where(queryParam.getTerms())
                .setWrapper(ResultWrappers.toList(tableTye))
                .execute().getResult();
        return PagerResult.of(total, list);
    }

    @Override
    public int count(QueryParam queryParam) {
        Map<String, String> count = (Map<String, String>) getDml().createSelectOperator()
                .from(metaTable.getTableName())
                .select("count(*) as count")
                .where(queryParam.getTerms())
                .setWrapper(ResultWrappers.singleMap())
                .execute().getResult();
        return Integer.parseInt(count.get("count"));
    }


    // 代码冗余优化：封装重复逻辑
    private List<JpaColumnMapper> getJpaColumnMapperList(E data) {
        return JpaEntityMapper.of(tableTye).dsl((IEntity) data).getJpaColumnMappers();
    }

}
